import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.Timer;

public class GUIFrame {
	/**
	 * Maximum amount of keywords allowed.
	 */
	private static final int MAX_WORDS = 10;
	
	/**
	 * Maximum amount of pages to retrieve.
	 */
	private static final int MAX_DEPTH = 10000;

	/**
	 * Timer to call tick methods.
	 */
	private Timer timer;

	/**
	 * Default settings for the keywords.
	 */
	private static final String DEFAULT_KEYWORDS = "intelligence,artificial,agent,university,research,science,robot";

	/**
	 * The main frame.
	 */
	private JFrame mainWindow;

	/**
	 * Textfield for the seed URL.
	 */
	private JTextField url_box;

	/**
	 * Textfield for the page depth.
	 */
	private JTextField depth_box;

	/**
	 * Textfield for the keywords.
	 */
	private JTextField keyword_box;

	/**
	 * Button to indicate multithreaded version should be run.
	 */
	private JRadioButton multi;

	/**
	 * Button to indicate singlethreaded version should be run.
	 */
	private JRadioButton single;

	/**
	 * Reporter that outputs all data.
	 */
	private Reporter reporter;

	/**
	 * PageToRetrieve buffer.
	 */
	private PageToRetrieve retbuff;

	/**
	 * Page retrieval limit.
	 */
	private int pageDepth;
	
	private JLabel runningLabel;
	
	/**
	 * Constructs and initializes frame.
	 */
	public GUIFrame() {
		mainWindow = new JFrame("Dysfunction's Web Crawler");
		initialize();
		// Default initialize frame stuff.
		mainWindow.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		mainWindow.pack();
		mainWindow.setVisible(true);
		retbuff = new PageToRetrieve(this);
		pageDepth = 0;
	}
	
	/**
	 * Initialize the GUI.
	 */
	private void initialize() {
		mainWindow.setLayout(new BorderLayout());
		mainWindow.add(inputSetUp(), BorderLayout.NORTH);
		mainWindow.add(outputSetUp(), BorderLayout.CENTER);
		runningLabel = new JLabel("Status: Stopped");
		mainWindow.add(runningLabel, BorderLayout.SOUTH);
		addCloseEvent();
	}
	
	/**
	 * Sets up the Output Panel.
	 * @return The panel that contains all the output information.
	 */
	private JPanel outputSetUp() {
		JPanel panel = new JPanel();
		reporter = new Reporter();
		panel.setLayout(new BorderLayout());
		panel.add(reporter, BorderLayout.CENTER);

		return panel;
	}
	
	/**
	 * Sets up any input boxes for information.
	 * @return Panel containing all the input boxes.
	 */
	private JPanel inputSetUp() {
		JPanel panel1 = new JPanel();
		JPanel panel2 = new JPanel();

		// url
		panel1.add(new JLabel("URL Seed:"));
		url_box = new JTextField(40);
		panel1.add(url_box);
		// depth
		panel1.add(new JLabel("Page Depth:"));
		depth_box = new JTextField(3);
		panel1.add(depth_box);
		//Threading choice buttons
		ButtonGroup bg = new ButtonGroup();
		multi = new JRadioButton("MultiThreaded");
		multi.setSelected(true);
		single = new JRadioButton("SingleThreaded");
		keyword_box = new JTextField(20);

		bg.add(multi);
		bg.add(single);
		panel2.add(new JLabel("Keywords:"));
		panel2.add(keyword_box);
		panel2.add(multi);
		panel2.add(single);
		panel2.add(searchButton());
		panel2.add(stopButton());

		JPanel panel = new JPanel();
		panel.setLayout(new GridLayout(2, 1));
		panel.add(panel1);
		panel.add(panel2);
		return panel;
	}
	
	/**
	 * Stops Timer from running.
	 */
	private void stopTimer() {
		if (timer != null && timer.isRunning()) {
			runningLabel.setText("Status: Stopped");
			timer.stop();
		}
	}
	
	/**
	 * Creates a button that stops all processing.
	 * @return A Button that stop all processing.
	 */
	private JButton stopButton() {
		JButton button = new JButton("Stop");
		button.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				stopTimer();
			}
		});
		return button;
	}
	
	/**
	 * Button that starts the search.
	 * @return
	 */
	private JButton searchButton() {
		JButton button = new JButton("Search");
		button.addActionListener(new ActionListener() {
			// this is where the reporter is supposed to get the keyword list...
			@Override
			public void actionPerformed(ActionEvent arg0) {
				ArrayList<String> keywords = new ArrayList<String>();
				stopTimer();
				retbuff = new PageToRetrieve(retbuff.getParent());
				reporter.setText("");
				System.out.flush();
				for (String s : keyword_box.getText().split(",")) {
					if (keywords.size() <= MAX_WORDS) {
						keywords.add(s.trim());
					}
				}

				reporter.setKeywords(keywords); // send the reporter the keywords
				reporter.append("\n");
				if (multi.isSelected()) {
					retbuff.setThreaded(true);

				} else if (single.isSelected()) {
					retbuff.setThreaded(false);

				}
				retbuff.setKeywords(keywords);
				retbuff.setSeed(url_box.getText());
				pageDepth = Integer.parseInt(depth_box.getText());
				if (pageDepth > MAX_DEPTH) pageDepth = MAX_DEPTH;
				retbuff.setPageCap(pageDepth);
				runningLabel.setText("Status: Running");
				startTimer();
			}

		});
		return button;
	}
	
	/**
	 * Adds a window event that listens for the close event that stops 
	 * all threads and timers.
	 */
	private void addCloseEvent() {
		mainWindow.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				stopTimer();
			}
		});
	}
	
	/**
	 * Progresses everything forward.
	 */
	public void tick() {
		runningLabel.setText(runningLabel.getText() + ".");
		retbuff.tick();
		boolean ret = retbuff.pagesRetrieved() == pageDepth;
		boolean dg = retbuff.pageBuffer().DataGather().isDone();
		if (ret && !dg)
			retbuff.pageBuffer().DataGather().tick();
		else if (ret && dg)
			stopTimer();
	}
	
	/**
	 * Starts Timer.
	 */
	public void startTimer() {
		timer = new Timer(0, new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				tick();
			}
		});
		timer.start();
	}
	
	/**
	 * Reporter.
	 * @return
	 */
	public Reporter reporter() {
		return reporter;
	}
	
	/**
	 * Starts Everything.
	 * @param args
	 */
	public static void main(String[] args) {
		new GUIFrame();	
	}
}
